﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace CheckFreeWayClient
{
    class TestaConexoes
    {
        private const int TAMANHO_HEADER = 10;

        public delegate void OnSendMessageDelegate(string strMessage, int port, string hostname);
        public event OnSendMessageDelegate OnSendMessage;

        public delegate void OnReceiveMessageDelegate(string strMessage, int port, string hostname);
        public event OnReceiveMessageDelegate OnReceiveMessage;

        public delegate void OnErrorSendingErrorDelegate(Exception ex, int port, string hostname);
        public event OnErrorSendingErrorDelegate OnErrorSending;

        public delegate void OnErrorReceivingErrorDelegate(Exception ex, int port, string hostname);
        public event OnErrorReceivingErrorDelegate OnErrorReceiving;

        public delegate void OnErrorConnectingDelegate(Exception ex, int port, string hostname);
        public event OnErrorConnectingDelegate OnErrorConnecting;

        public delegate void OnPortCheckedDelegate(int port);
        public event OnPortCheckedDelegate OnPortChecked;

        public delegate void OnEndPortCheckDelegate();
        public event OnEndPortCheckDelegate OnEndPortCheck;

        private int _portaInicial;
        private int _portaFinal;
        private string _hostname;

        public TestaConexoes(string hostname, int portaInicial, int portaFinal)
        {
            _portaInicial = portaInicial;
            _portaFinal = portaFinal;
            _hostname = hostname;
        }

        public void Testa(string message)
        {

            // Monta Resposta
            String msgEnvio = "0000000000";
            msgEnvio = msgEnvio + message.Length.ToString();
            msgEnvio = msgEnvio.Substring(msgEnvio.Length - TAMANHO_HEADER);

            msgEnvio = msgEnvio + message;

            // Envia Resposta

            for (int port = _portaInicial; port <= _portaFinal; port++)
            {
                if (OnPortChecked != null)
                    OnPortChecked(port);
                
                TcpClient sck;
                NetworkStream ns;
                StreamWriter sw;
                StreamReader sr;

                try
                {
                    
                    sck = new TcpClient();
                    sck.SendTimeout = 60000; // Milisegundos
                    sck.ReceiveTimeout = 60000; // Milisegundos
                    sck.Connect(_hostname, port);

                    while (!sck.Connected)
                        Thread.Sleep(1);

                }
                catch (Exception ex)
                {
                    if (OnErrorConnecting != null)
                        OnErrorConnecting(ex, port, _hostname);
                    continue;
                }

                try
                {
                    ns = sck.GetStream();
                    sw = new StreamWriter(ns);
                    sr = new StreamReader(ns);
                    sw.Write(msgEnvio);
                    sw.Flush();
                }
                catch (Exception ex)
                {
                    if (OnErrorSending != null)
                        OnErrorSending(ex, port, _hostname);
                    continue;
                }

                if (OnSendMessage != null)
                    OnSendMessage(msgEnvio,port,_hostname);

                try
                {
                    while (sck.Available < (msgEnvio.Length + 10)) // 10 = LEN(" Received!")
                        Thread.Sleep(1);

                    String strBody = sr.ReadToEnd();

                    if (OnReceiveMessage != null)
                        OnReceiveMessage(strBody, port, _hostname);

                }
                catch (Exception ex)
                {
                    if (OnErrorReceiving != null)
                        OnErrorReceiving(ex, port, _hostname);
                    continue;

                }

                sw.Dispose();
                sr.Dispose();
                ns.Dispose();
                sck.Close();
                Thread.Sleep(100);
            }
            OnEndPortCheck();
        }
    }
}
